#ifndef FHE_CORE_FILESYSTEM_H
#define FHE_CORE_FILESYSTEM_H

#include <fhe/core/Encoder.h>
#include <fhe/core/ISerializer.h>
#include <string>
#include <map>

namespace fhe
{
  namespace core
  {
    class FileSystem
    {
    public:
      static FileSystem& instance();
      ~FileSystem();
      
      void addPath( const std::string& path );
      bool hasFile( const std::string& filename ) const;
      std::string getFile( const std::string& filename ) const;
      std::string readFile( const std::string& filename ) const;
      std::string getExtension( const std::string& filename ) const;

      Data::Ptr load( const std::string& filename ) const;
      void save( const Data::Ptr& data, const std::string& filename ) const;
      
      bool hasEncoder( const std::string& extension ) const;
      Encoder::Ptr getEncoder( const std::string& extension ) const;
      void addEncoder( const Encoder::Ptr& dataStream );
      
      bool hasSerializer( const std::string& name ) const;
      bool hasSerializer( const std::type_info& type ) const;
      ISerializer::Ptr getSerializer( const std::string& name ) const;
      ISerializer::Ptr getSerializer( const std::type_info& type ) const;
      void addSerializer( const ISerializer::Ptr& serializer );
      
      template <typename T>
      void serialize( const Data::Ptr& data, T t ) const
      {
        Val val( t );
        getSerializer( typeid(T) )->serialize( data, val );
      }
      
      template <typename T>
      T deserialize( const Data::Ptr& data ) const
      {
        return getSerializer( typeid(T) )->deserialize( data ).get<T>();
      }
      
    private:
      FileSystem();
      FileSystem( const FileSystem& );
      void operator=( const FileSystem& );
      
      std::map< std::string, std::string > files_;
      std::vector< Encoder::Ptr > dataStreams_;
      std::vector< ISerializer::Ptr > serializers_;
    };
  }
}

#endif
